import { assert } from "cc";
import { IBaseBehavior } from "../base/IBaseBehavior";
import { IBehaviorTree } from "../base/IBehaviorTree";
import { BTContext } from "../BTContext";
import { BT_State, BT_Type } from "../BTDefine";
import { Blackboard } from "./Blackboard";
import { Composite } from "./composite/Composite";
import { Decorator } from "./decorator/Decorator";

export class BehaviorTree implements IBehaviorTree {

    private _context: BTContext = null;

    private _root: IBaseBehavior = null;
    private _isRunning = false;

    private _finishCallback: Function = null;

    constructor() {
        this._context = new BTContext;
        this._context.tree = this;
        this._context.blackboard = new Blackboard;
    }

    /**
     * 设置黑板报
     * @param blackboard 
     */
    public setBlackboard(blackboard: any) {
        if (this._context) {
            this._context.blackboard = blackboard;
        } else {
            assert(this._context, 'BTContext 还没有初始化');
        }
    }

    // 设置根节点
    public setRoot(node: IBaseBehavior) {
        this._root = node;
    }

    /**
     * 开始执行
     * @param cb 结束回调
     * @param immediate 是否立即执行，默认undefined，需要逐帧执行
     */
    public start(cb?: (ret: number) => void, immediate?: boolean) {
        this._finishCallback = cb;
        this._isRunning = true;

        this.reset();

        if (!immediate) {
            this.tick(0);
        }
        else {
            while (this._isRunning) {
                this.tick(0);
            }
        }
    }

    /**
     * 重置所有节点
     */
    public reset(): void {
        if (this._root) {
            let queue: IBaseBehavior[] = [];
            queue.push(this._root);

            let iter: number = 0;
            while (iter < queue.length) {
                let node = queue[iter++];
                if (node.getType() === BT_Type.TYPE_COMPOSITE) {
                    let composite = <Composite>node;
                    for (const node of composite.getChildren()) {
                        queue.push(node);
                    }
                } else if (node.getType() === BT_Type.TYPE_DECORATOR) {
                    let decorator = <Decorator>node;
                    queue.push(decorator.getChild());
                }

                node.reset();
            }
        }

    }

    /**
     * 停止执行，immediate为false时有效
     */
    public stop() {
        if (this._isRunning) {
            let ret = this._root.abort();
            this.__finish(ret);
        }
    }

    /**
     * 逐步执行
     * @param dt 
     */
    public tick(dt) {
        if (this._isRunning) {
            this._root.setContext(this._context);
            let ret = this._root.tick(dt);
            if (ret != BT_State.RUNNING) {
                this.__finish(ret);
            }
        }
    }

    /**
     * 
     * @returns 是否执行中
     */
    isRunning(): boolean {
        return this._isRunning;
    }

    private __finish(ret: number) {
        this._isRunning = false;

        this._finishCallback && this._finishCallback(ret);
    }
}
